import {App, HeadingCache, TFile, TFolder, Vault} from "obsidian";
import {slice} from "builtin-modules";


export default class HeadingGenerate {
	app: App;
	private upLevelHeadingSuggestions: Map<string, string[]>;
	private vaultStartLocation: string;
	private ignoredHeaders: Array<string>;
	private ignoredSuffixArray: Array<string>;

	constructor(app: App, vaultStartLocation: string, ignoredHeaders: Array<string>, ignoredSuffixArray: Array<string>) {
		this.app = app;
		this.vaultStartLocation = vaultStartLocation;
		this.ignoredHeaders = ignoredHeaders;
		this.ignoredSuffixArray = ignoredSuffixArray;
	}

	getUpLevelHeading(headingIndex: number, headingCandidates: HeadingCache[], headingChain: HeadingCache[]) {
		const currentHeading = headingCandidates[headingIndex];
		const level = currentHeading.level;
		if (level <= 2) {
			headingChain.push(currentHeading);
			return;
		}
		const upLevel = level - 1;
		for (let i = headingIndex; i--; i>= 0)
		{
			if (headingCandidates[i].level <= upLevel){ // 找到上一级heading
				headingChain.push(currentHeading);
				this.getUpLevelHeading(i, headingCandidates, headingChain);
				break;
			}
		}
	}
	getUpLevelHeadingRecursively(cachedHeadings: HeadingCache[]) : Map<HeadingCache, HeadingCache[]>{
		const upLevelHeadingsArray = cachedHeadings.map((item, i) => {
			const chain: HeadingCache[] = [];
			this.getUpLevelHeading(i, cachedHeadings, chain);
			return chain;
		});

		const upLevelHeadingsMap = new Map();
		for(const heading of upLevelHeadingsArray){
			upLevelHeadingsMap.set(heading[0], heading.slice(1));
		}
		return upLevelHeadingsMap;
	}
	getHeadings(): string[]{
		let headingSuggestions: string[] = [];

		const markdownFiles: TFile[] = [];
		const startLocation = this.vaultStartLocation.trim();
		const folderOrFile = this.app.vault.getAbstractFileByPath(startLocation);
		if (folderOrFile instanceof TFile) {
			markdownFiles.push(folderOrFile);
		} else if (folderOrFile instanceof TFolder) {
			Vault.recurseChildren(folderOrFile, (file => {
				if (file instanceof TFile && file.extension === "md") {
					markdownFiles.push(file);
				}
			}));
		}

		// const markdownFiles = this.app.vault.getMarkdownFiles();
		markdownFiles.sort((a, b) => {
			if (a.stat.ctime > b.stat.ctime) return -1;
			if (a.stat.ctime < b.stat.ctime) return 1;
			return 0;
		});

		// const upLevelHeadingSuggestions: Map<string, string> = new Map();
		this.upLevelHeadingSuggestions = new Map();
		markdownFiles.forEach((markFile: TFile) => {
			for (const ignoredSuffix of this.ignoredSuffixArray) {
				if (markFile.path.endsWith(ignoredSuffix)) {
					return null;
				}
			}
			if (this.app.metadataCache.getFileCache(markFile) && this.app.metadataCache.getFileCache(markFile).headings) {
				const cachedHeadings = this.app.metadataCache.getFileCache(markFile).headings;
				const upLevelHeadingsMap = this.getUpLevelHeadingRecursively(cachedHeadings);
				upLevelHeadingsMap.forEach((headingCacheArray, keyHeading) => {
					// headingCacheArray.push(keyHeading)
					const reversedArray = headingCacheArray.reverse();
					reversedArray.push(keyHeading)
					const upLevelHeadingsText: string[] = reversedArray.map(v => "#".repeat(v.level) + ` ${v.heading}`);
					// this.upLevelHeadingSuggestions.set("#".repeat(keyHeading.level) + ` ${keyHeading.heading}`, upLevelHeadingsText);
					this.upLevelHeadingSuggestions.set(keyHeading.heading, upLevelHeadingsText);
				});
				// console.log(upLevelHeadingsMap);
				if (cachedHeadings){
					headingSuggestions = headingSuggestions.concat(cachedHeadings.map((v) => {
						// return  "#".repeat(v.level) + ` ${v.heading} (${markFile.path})`;
						return  "#".repeat(v.level) + ` ${v.heading}`; // TODO: 最好加一个hint，但是去重要手动做
					}));
				}
			}
		});
		headingSuggestions = headingSuggestions.filter(heading => { return !this.ignoredHeaders.contains(heading); });
		return Array.from(new Set(headingSuggestions));
	}

	selectSuggestion(headingText: string, content: string): string {
		this.getHeadings();
		// const { editor } = this.context;
		let selectedHeadingText = headingText;
		// let newMap : Map<string, string[]> = new Map();
		// for (const [key, value] of this.upLevelHeadingSuggestions.entries()) {
		//   newMap.set(key.trimStart("#").trim(), value);
		// }

		const upLevelHeadingsText = this.upLevelHeadingSuggestions.get(selectedHeadingText);
		[selectedHeadingText] = upLevelHeadingsText.slice(-1);
		// const mdView = this.app.workspace.getActiveViewOfType(MarkdownView);
		// const content = mdView.data;
		let replacementWithUpLevel = "";
		if (!upLevelHeadingsText || upLevelHeadingsText.length <= 0) {
			throw Error(`upper level heading not found: ${headingText}`);
		}
		let topMostHeadingIndex = -1;
		for (const upLevelHeadingText of upLevelHeadingsText) {
			if (content.indexOf(upLevelHeadingText) === -1) { // JM：表示现在文档中没有过这一层目录
				replacementWithUpLevel = replacementWithUpLevel + "\n" + upLevelHeadingText;
			} else {
				topMostHeadingIndex += 1;
			}
		}

		let topMostHeadingText: string; // 找到必须存在的最上头的heading，目的是为了找到插入定位
		if (!this.upLevelHeadingSuggestions.get(headingText)){
			throw Error(`cannot found topMost heading for ${headingText}`);
		}
		if (this.upLevelHeadingSuggestions.get(headingText).length === 0){
			topMostHeadingText = headingText;
		} else {
			topMostHeadingText = this.upLevelHeadingSuggestions.get(headingText)[topMostHeadingIndex];
		}

		// const [topMostHeadingText] = this.upLevelHeadingSuggestions.get(upLevelHeadingsText.slice(-1)[0]); // TODO: 这段逻辑是有bug的，
		console.log(`topMostHeadingText: ${topMostHeadingText} headingText: ${headingText}`);
		const startOffset = content.indexOf(topMostHeadingText) + topMostHeadingText.length;
		content = content.slice(0, startOffset).trimEnd() + `\n${replacementWithUpLevel}\n` + content.slice(startOffset).trimStart();
		return content;
		// editor.replaceRange(replacementWithUpLevel, this.context.start, this.context.end);
	}
}

